﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BFlatCompile.Nodes
{
	public class DotDereference : Expression
	{
		public Expression Root { get; private set; }
		public string Step { get; private set; }
		public int StepIndex { get { return Variable.Table.GetId(this.Step); } }
		public object StaticReference { get; private set; }
		public bool IsThis { get; private set; } // This dot dereference resolved to the current class and the context is static, so it should pretend to work like "this".
		public Token Token { get; private set; }

		public DotDereference(Expression root, string step, Token token)
		{
			this.Root = root;
			this.Step = step;
			Variable.Table.Register(step);
			this.StaticReference = null;
			this.IsThis = false;
			this.Token = token;
		}

		// Determine if this represents a static reference or if it's a normal dot value.
		// If it's a static reference, that means the root is either a namespace or class
		// and the step is a member of that class. If the member is not a class or namespace
		// then the user failed to qualify their reference with "this" or the class name.
		public override void ResolveCode(Class c, Dictionary<object, object> parents)
		{
			this.Root.ResolveCode(c, parents);

			if (this.Root is Variable)
			{
				Variable v = (Variable)this.Root;
				if (v.StaticReference != null)
				{
					object child = null;
					if (v.StaticReference is Class)
					{
						Class rootClass = (Class)v.StaticReference;
						child = rootClass.GetMember(this.Step, true);
						if (child == null)
						{
							// TODO: need token info
							throw new ParserException(rootClass.FullName + " doesn't have a member called " + this.Step);
						}
					}
					else if (v.StaticReference is Namespace)
					{
						Namespace rootNamespace = (Namespace)v.StaticReference;
						child = rootNamespace.GetMember(this.Step);
						if (child == null)
						{
							throw new Exception(rootNamespace.FullName + " doesn't have a member called " + this.Step);
						}
					}

					if (child != null)
					{
						this.StaticReference = child;
					}
				}
			}
		}

		public override void ResolveClassToThis(Class c)
		{
			if (this.StaticReference == c)
			{
				this.IsThis = true;
			}
		}
	}
}
